package mornd.test2;

import lombok.val;
import org.springframework.boot.DefaultBootstrapContext;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.boot.context.event.EventPublishingRunListener;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.context.support.StandardServletEnvironment;

import java.lang.reflect.Constructor;
import java.util.List;

/**
 * @author: mornd
 * @dateTime: 2023/5/10 - 17:30
 * 手动发布 boot 的七大事件
 */
public class App {
    public static void main(String[] args) throws Exception {
        SpringApplication spring = new SpringApplication();

        spring.addListeners(event -> {
            if(event.getClass().toString().contains("boot.context.event")) {
                System.out.println("========> 收到自定义事件：" + event.getClass());
            } else {
                System.out.println("==>容器自身发布事件：" + event.getClass());
            }
        });


        // spring 提供的工具类，加载 spring.factories 文件下的类
        List<String> runListenerNames =
                SpringFactoriesLoader.loadFactoryNames(SpringApplicationRunListener.class, App.class.getClassLoader());

        for (String name : runListenerNames) {
            Class<?> clazz = Class.forName(name);
            Constructor<?> constructor = clazz.getDeclaredConstructor(SpringApplication.class, String[].class);
            EventPublishingRunListener publisher = (EventPublishingRunListener) constructor.newInstance(spring, args);

            DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
            // 启动中
            publisher.starting(bootstrapContext);

            // 环境信息准备完毕
            publisher.environmentPrepared(bootstrapContext, new StandardServletEnvironment());

            GenericWebApplicationContext context = new GenericWebApplicationContext();
            // spring 容器创建，并调用初始化器之后
            publisher.contextPrepared(context);

            //  所有 beanDefinition 加载完毕之后
            publisher.contextLoaded(context);

            // 调用 refresh 方法 （spring容器准备完毕，准备后处理器，初始化所有单例等）
            context.refresh();

            // refresh 方法调用完毕之后
            publisher.started(context);

            // 启动完毕
            publisher.running(context);

            // boot 程序启动过程中出现错误
            publisher.failed(context, new RuntimeException("boot starting exception"));

        }

    }
}
